home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / faxd / EverexSend.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  13KB  |  462 lines

  1. /*    $Header: /usr/people/sam/fax/faxd/RCS/EverexSend.c++,v 1.55 1994/04/08 20:28:19 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include <stdio.h>
  26. #include "Everex.h"
  27. #include "ModemConfig.h"
  28.  
  29. #include "t.30.h"
  30. #include "everex.h"
  31.  
  32. /*
  33.  * Send Protocol for ``old'' Class-1-style Everex modems.
  34.  */
  35.  
  36. CallStatus
  37. EverexModem::dialResponse()
  38. {
  39.     for (;;) {
  40.     switch (atResponse(rbuf, conf.dialResponseTimeout)) {
  41.     case AT_EMPTYLINE:    return (FAILURE);
  42.     case AT_TIMEOUT:    return (FAILURE);
  43.     case AT_BUSY:        return (BUSY);
  44.     case AT_NOCARRIER:    return (NOCARRIER);
  45.     case AT_NODIALTONE:    return (NODIALTONE);
  46.     case AT_NOANSWER:    return (NOANSWER);
  47.     case AT_ERROR:        return (ERROR);
  48.     case AT_OTHER:
  49.         if (strneq(rbuf, "FAX", 3))
  50.         return (OK);
  51.         break;
  52.     case AT_OK:
  53.         return (type == EV958 ? OK : FAILURE);    // XXX data connection?
  54.     }
  55.     }
  56. }
  57.  
  58. /*
  59.  * Begin a send operation.
  60.  */
  61. void
  62. EverexModem::sendBegin()
  63. {
  64.     atCmd("#S8=10#S9=30");    // s8 = retry count, s9 = retry interval
  65.     if (type == EV958)        // send 1100Hz tone
  66.     atCmd("#R#T1100=5");
  67.     params.br = (u_int) -1;    // force initial dcs setup
  68. }
  69.  
  70. /*
  71.  * Get the initial DIS and NSF information.
  72.  */
  73. fxBool
  74. EverexModem::getPrologue(Class2Params& params, u_int& nsf, fxStr& csi, fxBool& hasDoc)
  75. {
  76.     if (!atCmd("#FR01?", AT_NOTHING))    // fetch DIS bytes
  77.     return (FALSE);
  78.     nsf = 0;                // XXX AT#FR04?
  79.     csi = "";
  80.     switch (atResponse(rbuf, 10*1000)) {
  81.     case AT_OTHER:
  82.     break;
  83.     default:
  84.     (void) sync(2*1000);
  85.     /* fall thru... */
  86.     case AT_OK:
  87.     case AT_ERROR:
  88.     return (FALSE);
  89.     }
  90.     int n = strlen(rbuf);
  91.     dis = fromHex(rbuf, 6);
  92.     u_int xinfo = (dis&DIS_XTNDFIELD) && n >= 8 ? fromHex(rbuf+6, 2) : 0;
  93.     params.setFromDIS(dis, xinfo);
  94.     hasDoc = (dis & DIS_T4XMTR) != 0;        // documents to poll
  95.     // XXX get CSI
  96.     return (sync(2*1000) && (dis&DIS_T4RCVR));
  97. }
  98.  
  99. /*
  100.  * Setup file-independent parameters prior
  101.  * to entering Phase B of the send protocol.
  102.  */
  103. void
  104. EverexModem::sendSetupPhaseB()
  105. {
  106.     setupFrame(FCF_TSI|FCF_SNDR, (char*) lid);
  107. }
  108.  
  109. u_int EverexModem::modemPFMCodes[8] = {
  110.     FCF_MPS,        // PPM_MPS
  111.     FCF_EOM,        // PPM_EOM
  112.     FCF_EOP,        // PPM_EOP
  113.     FCF_EOP,        // 3 ??? XXX
  114.     FCF_PRI_MPS,    // PPM_PRI_MPS
  115.     FCF_PRI_EOM,    // PPM_PRI_EOM
  116.     FCF_PRI_EOP,    // PPM_PRI_EOP
  117.     FCF_EOP,        // 7 ??? XXX
  118. };
  119. int EverexModem::modemRateCodes[8] = {
  120.     S4_2400V27,        // V.27 2400
  121.     S4_4800V27,        // V.27 4800 XXX (maybe V29 instead?)
  122.     S4_7200V29,        // V.29 7200
  123.     S4_9600V29,        // V.29 9600
  124.     S4_9600V29,        // V.29 9600 (map 12000)
  125.     S4_9600V29,        // V.29 9600 (map 14400)
  126.     S4_9600V29,        // undefined
  127.     S4_9600V29,        // undefined
  128. };
  129. int EverexModem::modemScanCodes[8] = {
  130.     0,            // ST_0MS
  131.     5,            // ST_5MS
  132.     10,            // ST_10MS2
  133.     10,            // ST_10MS
  134.     20,            // ST_20MS2
  135.     20,            // ST_20MS
  136.     40,            // ST_40MS2
  137.     40,            // ST_40MS
  138. };
  139.  
  140. /*
  141.  * Send the specified document using the supplied
  142.  * parameters.  The pph is the post-page-handling
  143.  * indicators calculated prior to intiating the call.
  144.  */
  145. fxBool
  146. EverexModem::sendPhaseB(TIFF* tif, Class2Params& next, FaxMachineInfo& info,
  147.     fxStr& pph, fxStr& emsg)
  148. {
  149.     int ntrys = 0;            // # retraining/command repeats
  150.     fxBool transferOK = TRUE;
  151.     fxBool morePages = TRUE;
  152.  
  153.     do {
  154.     transferOK = !abortRequested();
  155.     if (!transferOK)
  156.          break;
  157.     /*
  158.      * Check the next page to see if the transfer
  159.      * characteristics change.  If so, update the
  160.      * current T.30 session parameters.
  161.      */
  162.     if (params != next) {
  163.         if (!sendTraining(next, emsg))
  164.         return (FALSE);
  165.         params = next;
  166.     }
  167.     transferOK = sendPage(tif, params, emsg);
  168.     if (!transferOK)
  169.         break;
  170.     /*
  171.      * Delay before switching to the low speed carrier to
  172.      * send the post-page-message frame.
  173.      */
  174.     pause(75);
  175.     /*
  176.      * Everything went ok, look for the next page to send.
  177.      */
  178.     morePages = !TIFFLastDirectory(tif);
  179.     int cmd;
  180.     // XXX check pph length
  181.     switch (pph[0]) {
  182.     default:
  183.         morePages = FALSE;
  184.         emsg = "Unknown post-page-handling indicator \"" | pph | "\"";
  185.         /* fall thru... */
  186.     case 'P': cmd = FCF_EOP; break;
  187.     case 'M': cmd = FCF_EOM; break;
  188.     case 'S': cmd = FCF_MPS; break;
  189.     }
  190.     int ncrp = 0;
  191.     u_int fcf;
  192.     do {
  193.         transferOK = sendPPM(cmd, emsg);
  194.         if (!transferOK)
  195.         break;
  196.         fcf = fromHex(rbuf+2, 2);
  197.         tracePPR("SEND recv", fcf);
  198.         switch (fcf) {
  199.         case FCF_RTP:        // ack, continue after retraining
  200.         transferOK = sendTraining(params, emsg);
  201.         next = params;        // avoid retraining above
  202.         /* fall thru... */
  203.         case FCF_MCF:        // ack confirmation
  204.         case FCF_PIP:        // ack, w/ operator intervention
  205.         countPage();        // update server
  206.         pph.remove(0);        // discard post-page-handling
  207.         ntrys = 0;
  208.         if (morePages)
  209.             transferOK = (TIFFReadDirectory(tif) &&
  210.             sendSetupParams(tif, next, info, emsg));
  211.         break;
  212.         case FCF_DCN:        // disconnect, abort
  213.         emsg = "Remote fax disconnected prematurely";
  214.         transferOK = FALSE;
  215.         break;
  216.         case FCF_RTN:        // nak, retry after retraining
  217.         if ((++ntrys % 2) == 0) {
  218.             /*
  219.              * Drop to a lower signalling rate and retry.
  220.              */
  221.             if (params.br == BR_2400) {
  222.             emsg = "Unable to transmit page"
  223.                    " (NAK at all possible signalling rates)";
  224.             transferOK = FALSE;
  225.             break;
  226.             }
  227.             params.br--;
  228.         }
  229.         if (transferOK = sendTraining(params, emsg)) {
  230.             morePages = TRUE;    // force continuation
  231.             next = params;    // avoid retraining above
  232.         }
  233.         break;
  234.         case FCF_PIN:        // nak, retry w/ operator intervention
  235.         emsg = "Unable to transmit page"
  236.                " (NAK with operator intervention)";
  237.         transferOK = FALSE;
  238.         break;
  239.         case FCF_CRP:
  240.         break;
  241.         default:            // unexpected abort
  242.         emsg = "Fax protocol error (unknown frame received)";
  243.         transferOK = FALSE;
  244.         break;
  245.         }
  246.     } while (fcf == FCF_CRP && ++ncrp < 3);
  247.     if (ncrp == 3) {
  248.         emsg = "Fax protocol error (command repeated 3 times)";
  249.         transferOK = FALSE;
  250.     }
  251.     } while (transferOK && morePages);
  252.     return (transferOK);
  253. }
  254.  
  255. /*
  256.  * Send capabilities and do training.
  257.  */
  258. fxBool
  259. EverexModem::sendTraining(Class2Params& params, fxStr& emsg)
  260. {
  261.     do {
  262.     u_int dcs = params.getDCS();
  263.     setupFrame(FCF_DCS|FCF_SNDR, dcs);
  264.     fxStr br(modemRateCodes[params.br&7], "#S4=%u");
  265.     fxStr st(modemScanCodes[params.st&7], "#S5=%u");
  266.     atCmd(br | st);
  267.     int t = 2;
  268.     do {
  269.         protoTrace("SEND training at %s",
  270.         Class2Params::bitRateNames[params.br]);
  271.         if (!sendFrame(FCF_TSI|FCF_SNDR, FCF_DCS|FCF_SNDR)) {
  272.         if (abortRequested())
  273.             return (FALSE);
  274.         protoTrace("Error sending T.30 prologue frames");
  275.         continue;
  276.         }
  277.         /*
  278.          * Delay before sending the TCF.
  279.          */
  280.         pause(75);
  281.         if (!atCmd("#P1")) {
  282.         if (abortRequested())
  283.             return (FALSE);
  284.         protoTrace("Problem sending TCF data");
  285.         }
  286.         char buf[1024];
  287.         if (getModemLine(buf, sizeof (buf), conf.t4Timer) > 2 && strneq(buf, "R ", 2))
  288.         switch (fromHex(buf+2, 2)) {
  289.         case FCF_CFR:        // training confirmed
  290.             protoTrace("TRAINING succeeded");
  291.             setDataTimeout(60, params.br);
  292.             return (TRUE);
  293.         case FCF_FTT:        // failure to train, retry
  294.             break;
  295.         case FCF_DCN|FCF_RCVR:    // disconnect
  296.             emsg = "Remote fax disconnected during training";
  297.             protoTrace("TRAINING failed");
  298.             goto done;
  299.         }
  300.         pause(1500);        // give other side time to reset
  301.     } while (--t > 0);
  302.     /*
  303.      * Two attempts at the current speed failed, drop
  304.      * the signalling rate to the next lower rate supported
  305.      * by the local & remote sides and try again.
  306.      */
  307.     } while (dropToNextBR(params));
  308.     emsg = "Failure to train remote modem";
  309. done:
  310.     protoTrace("TRAINING failed");
  311.     return (FALSE);
  312. }
  313.  
  314. #define    isCapable(br,dis)    ((dis & Class2Params::brDISTab[br]) != 0)
  315.  
  316. /*
  317.  * Select the next lower signalling rate that's
  318.  * acceptable to both local and remote sides.
  319.  */
  320. fxBool
  321. EverexModem::dropToNextBR(Class2Params& params)
  322. {
  323.     do {
  324.     if (params.br == BR_2400)
  325.         return (FALSE);
  326.     params.br--;
  327.     } while (selectSignallingRate(params.br) != params.br ||
  328.     !isCapable(params.br, dis));
  329.     return (TRUE);
  330. }
  331.  
  332. /*
  333.  * Wait for a signal from the modem that the high
  334.  * speed carrier was dropped (``M 4'').
  335.  */
  336. fxBool
  337. EverexModem::waitForCarrierToDrop(fxStr& emsg)
  338. {
  339.     int t = 3;
  340.     do {
  341.     if (getModemLine(rbuf, sizeof (rbuf), getDataTimeout()) > 2 && streq(rbuf, "M 4"))
  342.         return (TRUE);
  343.     } while (--t > 0);
  344.     emsg = "Unable to reestablish low speed carrier";
  345.     return (FALSE);
  346. }
  347.  
  348. const int EverexSendMode =
  349.     (S2_HOSTCTL|S2_DEFMSGSYS|S2_FLOWATBUF|S2_PADEOLS|S2_19200);
  350.  
  351. /*
  352.  * Send a page of facsimile data (pre-encoded).
  353.  */
  354. fxBool
  355. EverexModem::sendPage(TIFF* tif, const Class2Params& params, fxStr& emsg)
  356. {
  357.     fxBool rc = FALSE;
  358.     if (!modemFaxConfigure(EverexSendMode)) {
  359.     emsg = "Unable to configure modem";
  360.     return (rc);
  361.     }
  362.     if (!atCmd("#P5#P3#P6")) {        // switch modem & start transfer
  363.     emsg = "Unable to initiate page transfer";
  364.     return (rc);
  365.     }
  366.     if (setBaudRate(BR19200, FLOW_XONXOFF, FLOW_NONE)) {
  367.     protoTrace("SEND begin page");
  368.     u_long* stripbytecount;
  369.     (void) TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbytecount);
  370.     int totbytes = (int) stripbytecount[0];
  371.     if (totbytes > 0) {
  372.         u_char* buf = new u_char[totbytes];
  373.         if (TIFFReadRawStrip(tif, 0, buf, totbytes) >= 0) {
  374.         int sentbytes = 0;
  375.         /*
  376.          * Correct bit order of data if not what modem requires.
  377.          */
  378.         u_short fillorder = FILLORDER_MSB2LSB;
  379.         (void) TIFFGetField(tif, TIFFTAG_FILLORDER, &fillorder);
  380.         if (fillorder != FILLORDER_LSB2MSB)
  381.             TIFFReverseBits(buf, totbytes);
  382.         /*
  383.          * Pass data to modem, being careful not to hang.
  384.          */
  385.         beginTimedTransfer();
  386.         u_char* cp = buf;
  387.         while (totbytes > 0 && !wasTimeout() && !abortRequested()) {
  388.             int n = fxmin(totbytes, 1024);
  389.             if (!putModemData(cp, n))
  390.             break;
  391.             sentbytes += n;
  392.             cp += n;
  393.             totbytes -= n;
  394.             // XXX check to make sure RTC isn't in data
  395.         }
  396.         endTimedTransfer();
  397.         // return TRUE if no timeout
  398.         rc = (totbytes == 0) && !wasTimeout() && !abortRequested();
  399.         if (!rc)
  400.             emsg = "Timeout during transfer of page data";
  401.         protoTrace("SENT %d bytes of data", sentbytes);
  402.         }
  403.         delete buf;
  404.     }
  405.     if (rc) {
  406.         rc = sendRTC(params.is2D());
  407.         // TRUE =>'s be careful about flushing data
  408.         (void) sendBreak(TRUE);
  409.     } else
  410.         (void) sendBreak(FALSE);
  411.     (void) setBaudRate(EVEREX_CMDBRATE, FLOW_CURRENT, FLOW_XONXOFF);
  412.     protoTrace("SEND end page");
  413.     }
  414.     return (rc ? waitForCarrierToDrop(emsg) : FALSE);
  415. }
  416.  
  417. /*
  418.  * Send a 1d or 2d encoded RTC.
  419.  */
  420. fxBool
  421. EverexModem::sendRTC(fxBool is2D)
  422. {
  423.     static u_char RTC1D[] =
  424.     { 0x00, 0x08, 0x80, 0x00, 0x08, 0x80, 0x00, 0x08, 0x80 };
  425.     static u_char RTC2D[] =
  426.     { 0x00, 0x18, 0x00, 0x03, 0x60, 0x00, 0x0C, 0x80, 0x01, 0x30 };
  427.     protoTrace("SEND %s RTC", is2D ? "2D" : "1D");
  428.     return (is2D ?
  429.     putModemData(RTC2D, sizeof (RTC2D)) :
  430.     putModemData(RTC1D, sizeof (RTC1D)));
  431. }
  432.  
  433. /*
  434.  * Send the post-page-message and wait for a response.
  435.  */
  436. fxBool
  437. EverexModem::sendPPM(int ppm, fxStr& emsg)
  438. {
  439.     int t = 3;
  440.     do {
  441.     tracePPM("SEND send", ppm);
  442.     if (!sendFrame(ppm|FCF_SNDR)) {
  443.         if (!abortRequested())
  444.         emsg = "Problem sending post-page message frame";
  445.         return (FALSE);
  446.     }
  447.     if (getModemLine(rbuf, sizeof (rbuf), conf.t4Timer) > 2 && strneq(rbuf, "R ", 2))
  448.         return (TRUE);
  449.     } while (--t > 0);
  450.     emsg = "No response to MPS or EOP repeated 3 tries";
  451.     return (FALSE);
  452. }
  453.  
  454. /*
  455.  * Terminate a send operation.
  456.  */
  457. void
  458. EverexModem::sendEnd()
  459. {
  460.     sendFrame(FCF_DCN|FCF_SNDR);        // terminate session
  461. }
  462.